package models

import (
	"gintest/database"
	"github.com/jinzhu/gorm"
	"time"
	"strconv"
	"strings"
)

type Goods struct{
	Id int `json:"id" gorm:"column:id;primary_key" form:"id"`
	StoreId int `json:"store_id" gorm:"column:store_id" form:"store_id"`
	ClassId int `json:"class_id" gorm:"column:class_id" form:"class_id"`
	CustomId int `json:"custom_id" gorm:"column:custom_id" form:"custom_id"`
	Title string `json:"title" gorm:"column:title" form:"title"`
	Price float64 `json:"price" gorm:"column:price" form:"price"`
	Oprice float64 `json:"oprice" gorm:"column:oprice" form:"oprice"`
	Num int `json:"num" gorm:"column:num" form:"num"`
	Favorite int `json:"favorite" gorm:"column:favorite" form:"favorite"`
	Sales int `json:"sales" gorm:"column:sales" form:"sales"`
	Thumb string `json:"thumb" gorm:"column:thumb" form:"thumb"`
	Status int `json:"status" gorm:"column:status" form:"status"`
	CreateAt time.Time  `json:"create_at" gorm:"column:create_at;type:datetime" time_format:"2006-01-02 15:04:05" form:"create_at"`
	UpdateAt time.Time  `json:"update_at" gorm:"column:update_at;type:datetime" time_format:"2006-01-02 15:04:05" form:"update_at"`
	DeleteAt time.Time  `json:"delete_at" gorm:"column:delete_at;type:datetime" time_format:"2006-01-02 15:04:05" form:"delete_at"`
	//属于关系
	Store Store `json:"store" gorm:"ForeignKeyId:StoreId;AssociationForeignKey:Id"`
	GoodsClass  GoodsClass `json:"goods_class" gorm:"ForeignKey:ClassId;AssociationForeignKey:Id"`
	StoreCustomClass  StoreCustomClass `json:"store_custom_class" gorm:"ForeignKey:CustomId;AssociationForeignKey:Id"`
	//包含关系
	GoodsContent  GoodsContent `json:"goods_content" gorm:"ForeignKey:GoodsId;AssociationForeignKey:Id"`
	GoodsSpec  []GoodsSpec `json:"goods_spec" gorm:"ForeignKey:GoodsId;AssociationForeignKey:Id"`
	GoodsAttr []GoodsAttr `json:"goods_attr" gorm:"ForeignKey:GoodsId;AssociationForeignKey:Id"`
	GoodsImage []GoodsImage `json:"goods_image" gorm:"ForeignKey:GoodsId;AssociationForeignKey:Id"`
}
func (Goods) TableName() string {
	return "goods"
}

func GetGoodsList(page uint64,pagesize uint64,keyword string,store_id,status uint64)(data []Goods,total uint64){
	var offset=(page-1)*pagesize
	db:=database.SqlDB.Model(Goods{})

	if len(keyword)!=0{
		db=db.Where("concat(id,title) like ?","%"+keyword+"%")
	}
	if store_id!=0 {
		db=db.Where("store_id=?",store_id)
	}
	if status!=0 {
		db=db.Where("status=?",status)
	}
	db=db.Where("delete_at = 0 or delete_at is null")

	db.Preload("Store").Preload("GoodsClass").Preload("StoreCustomClass").Offset(offset).Limit(pagesize).Order("id desc").Find(&data)

	db.Model(Goods{}).Count(&total)
	return data,total
}
func GetGoodsListOfStore(page uint64,pagesize uint64,keyword string,store_id,status int,sort,custom_id int)(data []Goods){
	var offset=(page-1)*pagesize
	db:=database.SqlDB.Model(Goods{})

	if len(keyword)!=0{
		db=db.Where("title like ?","%"+keyword+"%")
	}
	if store_id!=0 {
		db=db.Where("store_id=?",store_id)
	}
	if status!=0 {
		db=db.Where("status=?",status)
	}
	if sort==0{//最新
		db=db.Order("id desc")
	}else if sort==1{//热卖
		db=db.Order("sales desc")
	}else if sort==2{//综合
		db=db.Order("id,sales desc")
	}

	if custom_id>0{
		//获取所有子分类
		var custorm_list []StoreCustomClass
		database.SqlDB.Model(StoreCustomClass{}).Where("store_id = ?",store_id).Where("parent_id = ?",custom_id).Find(&custorm_list)
		var ids []int
		for _,v:=range custorm_list{
			ids=append(ids,v.Id)
		}
		if len(ids)>0{
			database.SqlDB.Model(StoreCustomClass{}).Where("store_id = ?",store_id).Where("parent_id in (?)",ids).Find(&custorm_list)
			for _,v:=range custorm_list{
				ids=append(ids,v.Id)
			}
		}
		ids=append(ids,custom_id)
		db=db.Where("custom_id in (?)",ids)
	}
	db=db.Where("num > 0")
	db=db.Where("delete_at = 0 or delete_at is null")

	db.Preload("StoreCustomClass").Offset(offset).Limit(pagesize).Find(&data)
	return data
}
func AddGoods(data *Goods) error{
	if data.UpdateAt.IsZero(){
		data.UpdateAt=time.Now()
	}
	if data.CreateAt.IsZero(){
		data.CreateAt=time.Now()
	}
	return database.SqlDB.Model(Goods{}).Omit("Store","GoodsClass","StoreCustomClass","GoodsAttr","GoodsSpec").Create(data).Error
}
func DelGoodsByIds(ids []int) error{
	//return database.SqlDB.Model(User{}).Where("id in (?)",ids).Delete(User{}).Error
	return database.SqlDB.Model(Goods{}).Where("id in (?) and (delete_at = 0 or delete_at is null)",ids).Update("delete_at",time.Now().Local().String()).Error
}
func GetGoodsById(id int) (data Goods){
	database.SqlDB.Model(Goods{}).Preload("Store").Preload("GoodsClass").Preload("StoreCustomClass").Preload("GoodsContent").Preload("GoodsImage").Preload("GoodsSpec",func(db *gorm.DB) *gorm.DB {
		return db.Order("price asc")
	}).Preload("GoodsAttr",func(db *gorm.DB) *gorm.DB {
		return db.Order("attribute_id asc")
	}).Preload("GoodsAttr.GoodsAttribute").Preload("GoodsAttr.GoodsAttribute.GoodsAttributeValue").Where("id=?",id).First(&data);
	return data
}
func EditGoodsById(data *Goods) error{
	if data.UpdateAt.IsZero(){
		data.UpdateAt=time.Now()
	}
	tx:=database.SqlDB.Begin()
	err:=tx.Where("goods_id=?",data.Id).Delete(&GoodsImage{}).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	err=tx.Where("goods_id=?",data.Id).Delete(&GoodsContent{}).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	err=tx.Model(Goods{}).Omit("StoreId","ClassId","Store","GoodsClass","StoreCustomClass","GoodsAttr","GoodsSpec").Save(data).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}
func EditGoodsStatusById(id,status uint64) error{
	return database.SqlDB.Model(Goods{}).Where("id=?",id).Update("status",status).Error
}
func GetGoodsAttr(goods_id,attribute_id int)(data GoodsAttr){
	database.SqlDB.Model(GoodsAttr{}).Preload("GoodsAttribute").Preload("GoodsAttribute.GoodsAttributeValue").Where("goods_id=? and attribute_id=?",goods_id,attribute_id).Find(&data)
	return
}
func AddGoodsAttr(data GoodsAttr) error{
	err:=database.SqlDB.Model(GoodsAttr{}).Create(&data).Error
	if err!=nil{
		return err
	}
	err=calcSpec(data.GoodsId)
	if err!=nil{
		return err
	}
	return nil
}
func EditGoodsAttr(data GoodsAttr) error{
	tx:=database.SqlDB.Begin()
	var val_ids []int
	for i:=0;i<len(data.GoodsAttribute.GoodsAttributeValue);i++{
		val_ids=append(val_ids,data.GoodsAttribute.GoodsAttributeValue[i].Id)
	}
	err:=tx.Model(GoodsAttributeValue{}).Where("id not in (?) and attribute_id = ?",val_ids,data.AttributeId).Delete(GoodsAttributeValue{}).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	err=tx.Model(GoodsAttribute{}).Save(&data.GoodsAttribute).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	tx.Commit()
	err=calcSpec(data.GoodsId)
	if err!=nil{
		return err
	}
	return nil
}
func DelGoodsAttr(goods_id,attribute_id int) error{
	tx:=database.SqlDB.Begin()
	err:=tx.Where("goods_id=? and attribute_id=?",goods_id,attribute_id).Delete(GoodsAttr{}).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	err=tx.Where("id=?",attribute_id).Delete(GoodsAttribute{}).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	err=tx.Where("attribute_id=?",attribute_id).Delete(GoodsAttributeValue{}).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	tx.Commit()

	err=calcSpec(goods_id)
	if err!=nil{
		return err
	}
	return nil
}
func SaveGoodsSpec(data []GoodsSpec) error{
	tx:=database.SqlDB.Begin()
	for i:=0;i<len(data);i++{
		err:=tx.Model(GoodsSpec{}).Save(&data[i]).Error
		if err!=nil{
			tx.Rollback()
			return err
		}
	}
	tx.Commit()
	return nil
}
func calcSpec(goods_id int) error{
	tx:=database.SqlDB.Begin()
	//删除原来spec
	err:=tx.Model(GoodsSpec{}).Where("goods_id=?",goods_id).Delete(GoodsSpec{}).Error
	if err!=nil{
		tx.Rollback()
		return err
	}

	//获取所有属性
	var data []GoodsAttr
	err=tx.Model(GoodsAttr{}).Where("goods_id=?",goods_id).Preload("GoodsAttribute").Preload("GoodsAttribute.GoodsAttributeValue").Order("attribute_id asc").Find(&data).Error
	if err!=nil{
		tx.Rollback()
		return err
	}
	if len(data)==0{
		return nil
	}
	//生成笛卡尔积
	var val_list [][]GoodsAttributeValue
	for i:=0;i<len(data);i++{
		val_list=append(val_list,data[i].GoodsAttribute.GoodsAttributeValue)
	}
	attr_list:=product(val_list)
	//组建新的spec
	for i:=0;i<len(attr_list);i++{
		title:=""
		code:=""
		for j:=0;j<len(attr_list[i]);j++{
			title+=attr_list[i][j].Title+"/"
			code+=strconv.Itoa(attr_list[i][j].Id)+","
		}
		spec:=GoodsSpec{
			GoodsId:goods_id,
			Title:strings.TrimRight(title,"/"),
			SpecCode:strings.TrimRight(code,","),
		}
		err:=tx.Model(GoodsSpec{}).Create(&spec).Error
		if err!=nil{
			tx.Rollback()
			return err
		}
	}
	
	tx.Commit()
	return nil
}

func product(sets [][]GoodsAttributeValue) [][]GoodsAttributeValue {
	lens := func(i int) int { return len(sets[i]) }
	product := [][]GoodsAttributeValue{}
	for ix := make([]int, len(sets)); ix[0] < lens(0); nextIndex(ix, lens) {
		var r []GoodsAttributeValue
		for j, k := range ix {
			r = append(r, sets[j][k])
		}
		product = append(product, r)
	}
	return product
}
 
func nextIndex(ix []int, lens func(i int) int) {
	for j := len(ix) - 1; j >= 0; j-- {
		ix[j]++
		if j == 0 || ix[j] < lens(j) {
			return
		}
		ix[j] = 0
	}
}